// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use serde::{Serialize, Serializer};
use thiserror::Error;

/// All errors that can occur while running the updater.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Error {
    /// Endpoints are not sent.
    #[error("Updater does not have any endpoints set.")]
    EmptyEndpoints,
    /// IO errors.
    #[error(transparent)]
    Io(#[from] std::io::Error),
    /// Semver errors.
    #[error(transparent)]
    Semver(#[from] semver::Error),
    /// Serialization errors.
    #[error(transparent)]
    Serialization(#[from] serde_json::Error),
    /// Could not fetch a valid response from the server.
    #[error("Could not fetch a valid release JSON from the remote")]
    ReleaseNotFound,
    /// Unsupported app architecture.
    #[error("Unsupported application architecture, expected one of `x86`, `x86_64`, `arm` or `aarch64`.")]
    UnsupportedArch,
    /// Operating system is not supported.
    #[error("Unsupported OS, expected one of `linux`, `darwin` or `windows`.")]
    UnsupportedOs,
    /// Failed to determine updater package extract path
    #[error("Failed to determine updater package extract path.")]
    FailedToDetermineExtractPath,
    /// Url parsing errors.
    #[error(transparent)]
    UrlParse(#[from] url::ParseError),
    /// `reqwest` crate errors.
    #[error(transparent)]
    Reqwest(#[from] reqwest::Error),
    /// The platform was not found in the updater JSON response.
    #[error("the platform `{0}` was not found in the response `platforms` object")]
    TargetNotFound(String),
    /// Neither the platform nor the fallback platform was found in the updater JSON response.
    #[error(
        "None of the fallback platforms `{0:?}` were found in the response `platforms` object"
    )]
    TargetsNotFound(Vec<String>),
    /// Download failed
    #[error("`{0}`")]
    Network(String),
    /// `minisign_verify` errors.
    #[error(transparent)]
    Minisign(#[from] minisign_verify::Error),
    /// `base64` errors.
    #[error(transparent)]
    Base64(#[from] base64::DecodeError),
    /// UTF8 Errors in signature.
    #[error("The signature {0} could not be decoded, please check if it is a valid base64 string. The signature must be the contents of the `.sig` file generated by the Tauri bundler, as a string.")]
    SignatureUtf8(String),
    #[cfg(all(target_os = "windows", feature = "zip"))]
    /// `zip` errors.
    #[error(transparent)]
    Extract(#[from] zip::result::ZipError),
    /// Temp dir is not on same mount mount. This prevents our updater to rename the AppImage to a temp file.
    #[error("temp directory is not on the same mount point as the AppImage")]
    TempDirNotOnSameMountPoint,
    #[error("binary for the current target not found in the archive")]
    BinaryNotFoundInArchive,
    #[error("failed to create temporary directory")]
    TempDirNotFound,
    #[error("Authentication failed or was cancelled")]
    AuthenticationFailed,
    #[error("Failed to install .deb package")]
    DebInstallFailed,
    #[error("Failed to install package")]
    PackageInstallFailed,
    #[error("invalid updater binary format")]
    InvalidUpdaterFormat,
    #[error(transparent)]
    Http(#[from] http::Error),
    #[error(transparent)]
    InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
    #[error(transparent)]
    InvalidHeaderName(#[from] http::header::InvalidHeaderName),
    #[error("Failed to format date")]
    FormatDate,
    /// The configured updater endpoint must use a secure protocol like `https`
    #[error("The configured updater endpoint must use a secure protocol like `https`.")]
    InsecureTransportProtocol,
    #[error(transparent)]
    Tauri(#[from] tauri::Error),
}

impl Serialize for Error {
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.to_string().as_ref())
    }
}

pub type Result<T> = std::result::Result<T, Error>;
